package controller

import (
	"blog_server/middleware"
	"blog_server/model"
	"blog_server/utils"
	"fmt"
	"github.com/gin-gonic/gin"
	"golang.org/x/crypto/bcrypt"
	"net/http"
	"strconv"
)

func Register(c *gin.Context) {
	var newUser model.UserRegisterRequest

	err := c.ShouldBindJSON(&newUser)
	if err != nil {
		utils.Fail(c, nil)
		return
	}

	userName := newUser.UserName
	phoneNumber := newUser.PhoneNumber
	password := newUser.Password

	var user model.User
	db := model.GetDB()
	db.Where("phone_number = ?", phoneNumber).First(&user)

	if user.ID != 0 {
		utils.Fail(c, nil)
		return
	}

	hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
	RegisteredUser := model.User{
		PhoneNumber: phoneNumber,
		Password:    string(hashedPassword),
		UserName:    userName,
		Avatar:      "/images/default_avatar1.png",
	}
	db.Create(&RegisteredUser)

	utils.Success(c, nil)
}

func Login(c *gin.Context) {
	var requestedUser model.UserLoginRequest
	err := c.ShouldBindJSON(&requestedUser)
	if err != nil {
		utils.Fail(c, nil)
	}

	password := requestedUser.Password
	phoneNumber := requestedUser.PhoneNumber

	var user model.User
	db := model.GetDB()
	db.Where("phone_number = ?", phoneNumber).First(&user)
	if user.ID == 0 {
		utils.Fail(c, nil)
		return
	}

	err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
	if err != nil {
		utils.Fail(c, nil)
		return
	}

	token, err := middleware.ReleaseToken(user)
	if err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{
			"code": 500,
			"msg":  "系统异常",
		})
	}

	utils.Success(c, gin.H{"token": token})
}

func GetInfo(c *gin.Context) {
	user, _ := c.Get("user")
	utils.Success(c, gin.H{"id": user.(model.User).ID, "avatar": user.(model.User).Avatar})
}

func GetInfoByPhoneNumber(c *gin.Context) {
	phoneNumber := c.Param("phone_number")
	db := model.GetDB()

	var user model.User
	db.Where("phone_number = ?", phoneNumber).First(&user)

	if user.ID == 0 {
		utils.Fail(c, nil)
		return
	}

	utils.Success(c, gin.H{"id": user.ID})
}

func GetBriefInfo(c *gin.Context) {
	db := model.GetDB()
	var tgUser model.User
	tgUserId := c.Params.ByName("id")
	//curUser, _ := c.Get("user")

	userid, _ := strconv.Atoi(tgUserId)

	db.Where("id = ?", userid).Find(&tgUser)
	fmt.Println("curUser is nil")
	if tgUser.ID == 0 {
		utils.Fail(c, nil)
		return
	}
	utils.Success(c, gin.H{"id": tgUser.ID, "name": tgUser.UserName, "avatar": tgUser.Avatar})
	return
}

func GetDetailedInfo(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	userId, _ := strconv.Atoi(c.Params.ByName("id"))

	var curUser model.User
	if uint(userId) == user.(model.User).ID {
		curUser = user.(model.User)
	} else {
		db.Where("id = ?", userId).Find(&curUser)
		if curUser.ID == 0 {
			utils.Fail(c, nil)
			return
		}
	}

	var articleList, collectList []model.ArticleInfo
	var Followers, Following []model.UserInfo

	db.Model(&model.Article{}).Select("articles.id, articles.category_id, categories.category_name, articles.title, "+
		"articles.head_image, articles.read_cnt, articles.created_at, articles.updated_at").
		Joins("left join categories on articles.category_id = categories.id").
		//Joins("left join users on articles.user_id = users.id").
		Where("articles.user_id = ?", curUser.ID).
		Find(&articleList)

	db.Model(&model.Collect{}).Select("articles.id, articles.category_id, categories.category_name, articles.title, "+
		"articles.head_image, articles.read_cnt, articles.created_at, articles.updated_at").
		Joins("left join articles on collects.article_id = articles.id").
		//Joins("left join users on collects.user_id = users.id").
		Joins("left join categories on articles.category_id = categories.id").
		Where("collects.user_id = ?", curUser.ID).
		Find(&collectList)

	db.Model(&model.Follow{}).Select("users.id, users.avatar, users.user_name").
		Joins("left join users on follows.follower_id = users.id").
		Where("follows.followee_id = ?", curUser.ID).
		Find(&Followers)

	db.Model(&model.Follow{}).Select("users.id, users.avatar, users.user_name").
		Joins("left join users on follows.followee_id = users.id").
		Where("follows.follower_id = ?", curUser.ID).
		Find(&Following)

	for index, article := range articleList {
		var commentsCnt int64
		articleId := article.ID
		db.Model(&model.Comment{}).Where("article_id = ?", articleId).Count(&commentsCnt)
		//article.CommentCnt = uint(commentsCnt)
		fmt.Println(commentsCnt)
		articleList[index].CommentCnt = uint(commentsCnt)
	}

	for index, article := range collectList {
		var commentsCnt int64
		articleId := article.ID
		db.Model(&model.Comment{}).Where("article_id = ?", articleId).Count(&commentsCnt)
		//article.CommentCnt = uint(commentsCnt)
		fmt.Println(commentsCnt)
		collectList[index].CommentCnt = uint(commentsCnt)
	}

	utils.Success(c, gin.H{"id": curUser.ID, "name": curUser.UserName, "avatar": curUser.Avatar,
		"loginId": user.(model.User).ID, "articles": articleList, "collects": collectList,
		"following": Following, "follower": Followers})
}

func UpdateName(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")

	var requestedUser model.UserUpdateNameRequest
	err := c.ShouldBindJSON(&requestedUser)
	if err != nil {
		utils.Fail(c, nil)
	}

	userName := requestedUser.NewName
	var curUser model.User
	db.Where("id = ?", user.(model.User).ID).First(&curUser)
	if err := db.Model(&curUser).Update("user_name", userName).Error; err != nil {
		utils.Fail(c, nil)
	}

	utils.Success(c, nil)
}

func UpdatePassword(c *gin.Context) {
	db := model.GetDB()
	var requestedUser model.UserUpdatePasswordRequest
	err := c.ShouldBindJSON(&requestedUser)
	if err != nil {
		utils.Fail(c, nil)
		return
	}

	userId := requestedUser.Id
	password := requestedUser.NewPassword

	var curUser model.User
	db.Where("id = ?", userId).First(&curUser)
	if curUser.ID == 0 {
		utils.Fail(c, nil)
		return
	}

	if err := bcrypt.CompareHashAndPassword([]byte(curUser.Password), []byte(password)); err == nil {
		c.JSON(http.StatusOK, gin.H{"code": 400, "msg": "新密码不能与老密码一致"})
		return
	}

	hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)

	if err := db.Model(&curUser).Update("password", hashedPassword).Error; err != nil {
		c.JSON(http.StatusInternalServerError, gin.H{"code": 400, "msg": "修改失败"})
		return
	}

	c.JSON(http.StatusOK, gin.H{"code": 200, "msg": "修改成功"})
}

func UpdateAvatar(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	var requestedUser model.UserUpdateAvatarRequest
	err := c.ShouldBindJSON(&requestedUser)
	if err != nil {
		utils.Fail(c, nil)
	}

	var curUser model.User
	avatar := requestedUser.NewAvatar
	db.Where("id = ?", user.(model.User).ID).First(&curUser)
	if err := db.Model(&curUser).Update("avatar", avatar).Error; err != nil {
		utils.Fail(c, nil)
	}
	utils.Success(c, nil)
}

func Followed(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	FolloweeId := c.Params.ByName("id")

	var follow model.Follow
	db.Where("followee_id = ? and follower_id = ?", FolloweeId, user.(model.User).ID).First(&follow)
	if follow.FollowerId == 0 || follow.FolloweeId == 0 {
		utils.Success(c, gin.H{"followed": false})
		return
	}
	utils.Success(c, gin.H{"followed": true})
}

func Following(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	FolloweeId, _ := strconv.Atoi(c.Params.ByName("id"))

	follow := model.Follow{
		FollowerId: user.(model.User).ID,
		FolloweeId: uint(FolloweeId),
	}
	db.Create(&follow)

	utils.Success(c, nil)
}

func UnFollowing(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	FolloweeId, _ := strconv.Atoi(c.Params.ByName("id"))

	follow := model.Follow{
		FollowerId: user.(model.User).ID,
		FolloweeId: uint(FolloweeId),
	}
	db.Where("followee_id = ? and follower_id = ?", FolloweeId, user.(model.User).ID).Delete(&follow)

	utils.Success(c, nil)
}

func Collected(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	// 获取article的id
	articleId := c.Params.ByName("id")

	var collection model.Collect
	db.Where("user_id = ? and article_id = ?", user.(model.User).ID, articleId).First(&collection)

	if collection.ArticleId == 0 || collection.UserId == 0 {
		utils.Success(c, gin.H{"collected": false})
		return
	}
	utils.Success(c, gin.H{"collected": true})
}

func NewCollect(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	articleId, _ := strconv.Atoi(c.Params.ByName("id"))

	collect := model.Collect{
		UserId:    user.(model.User).ID,
		ArticleId: uint(articleId),
	}

	db.Create(&collect)

	utils.Success(c, nil)
}

func UnCollect(c *gin.Context) {
	db := model.GetDB()
	user, _ := c.Get("user")
	articleId, _ := strconv.Atoi(c.Params.ByName("id"))

	collect := model.Collect{
		UserId:    user.(model.User).ID,
		ArticleId: uint(articleId),
	}

	fmt.Println(user.(model.User).ID, articleId)

	if err := db.Where("user_id = ? and article_id = ?", user.(model.User).ID, articleId).Delete(&collect).Error; err != nil {
		fmt.Println(err)
		utils.Fail(c, nil)
	}

	utils.Success(c, nil)
}
